{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sP8PQnz1QrcF"
      },
      "source": [
        "##### Copyright 2025 Google LLC."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "ca23c3f523a7"
      },
      "outputs": [],
      "source": [
        "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bxGr_x3MRA0z"
      },
      "source": [
        "# Gemini API: Text Summarization\n",
        "\n",
        "<a target=\"_blank\" href=\"https://colab.research.google.com/github/google-gemini/cookbook/blob/main/examples/json_capabilities/Text_Summarization.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" height=30/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ysy--KfNRrCq"
      },
      "source": [
        "You will use Gemini API's JSON capabilities to extract characters, locations, and summary of the plot from a story."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ne-3gnXqR0hI"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\u001b[?25l   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.0/141.0 kB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K   \u001b[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[91m╸\u001b[0m\u001b[90m━━\u001b[0m \u001b[32m133.1/141.0 kB\u001b[0m \u001b[31m85.0 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m141.0/141.0 kB\u001b[0m \u001b[31m3.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h"
          ]
        }
      ],
      "source": [
        "%pip install -U -q \"google-genai>=1.0.0\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eomJzCa6lb90"
      },
      "source": [
        "## Configure your API key\n",
        "\n",
        "To run the following cell, your API key must be stored it in a Colab Secret named `GOOGLE_API_KEY`. If you don't already have an API key, or you're not sure how to create a Colab Secret, see [Authentication](https://github.com/google-gemini/cookbook/blob/main/quickstarts/Authentication.ipynb) for an example."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "v-JZzORUpVR2"
      },
      "outputs": [],
      "source": [
        "from google.colab import userdata\n",
        "from google import genai\n",
        "\n",
        "GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')\n",
        "client = genai.Client(api_key=GOOGLE_API_KEY)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kNE5XslpPpT0"
      },
      "source": [
        "## Example"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8V5lHRmkNejR"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "The flickering candlelight cast dancing shadows across Elara's face as she hunched over the ancient map. The vellum felt brittle beneath her fingertips, the ink faded and smudged with age. She traced a delicate line with her calloused finger, following a treacherous path winding through the jagged peaks of the Dragon's Tooth mountains. Elara, a cartographer by trade but an adventurer at heart, had spent years deciphering this cryptic document, rumored to lead to the lost city of Eldoria.\n",
              "\n",
              "Eldoria, a civilization whispered about in hushed tones in the taverns of Whisperwind village, was said to have vanished overnight, leaving behind only legends of unimaginable riches and powerful magic. Skeptics dismissed it as a fanciful tale, a bedtime story spun to entertain children. But Elara knew better. She felt the truth of Eldoria resonating within her soul, a siren's call that echoed in her blood.\n",
              "\n",
              "The map indicated a hidden passage, a forgotten route known only to the Eldorians, that bypassed the most dangerous parts of the mountains. According to the legends, the passage was guarded by a creature of stone and shadow, a protector tasked with preventing outsiders from defiling Eldoria's secrets. Elara shivered, not from fear, but from anticipation.\n",
              "\n",
              "Gathering her supplies, Elara carefully packed dried rations, a waterskin, a bedroll, and her trusty map. She also included a small, intricately carved wooden flute, a gift from her grandfather, a skilled musician who believed that even the most fearsome beasts could be soothed by a beautiful melody. With a deep breath, she extinguished the candle and stepped out into the cool night air.\n",
              "\n",
              "Her journey began under the watchful gaze of the moon, a silver disc hanging high in the inky sky. As she trekked towards the Dragon's Tooth mountains, the landscape grew increasingly rugged. Towering cliffs loomed above, their peaks piercing the heavens like jagged teeth. The wind howled through the canyons, carrying with it the mournful cries of unseen creatures.\n",
              "\n",
              "Days turned into nights as Elara navigated the treacherous terrain. She battled fierce winds, scaled sheer rock faces, and forded icy streams. She encountered wild creatures, some hostile, others indifferent, but none as terrifying as the guardian of the hidden passage. Finally, after what felt like an eternity, she arrived at the foot of a colossal stone archway, partially concealed by a curtain of cascading vines. This, she knew, was the entrance to the forgotten route.\n",
              "\n",
              "As Elara approached the archway, a deep rumbling sound echoed through the mountains. The ground beneath her feet trembled, and the vines covering the archway began to writhe and twist. Emerging from the shadows was a creature of immense size, its body composed of jagged rocks and swirling shadows. Its eyes glowed with an eerie green light, and its voice resonated with the weight of centuries. \"Turn back, mortal,\" it boomed, its words shaking the very air. \"Eldoria is not for you.\"\n",
              "\n",
              "Elara stood her ground, her heart pounding in her chest. She knew that she couldn't defeat the creature in a physical battle. She reached into her satchel and pulled out the wooden flute. Closing her eyes, she took a deep breath and began to play. The notes, clear and pure, filled the air, weaving a melody of longing and hope, of courage and perseverance.\n",
              "\n",
              "The creature of stone and shadow paused, its glowing eyes dimming slightly. The music seemed to resonate with its ancient soul, stirring memories of a time long past. As the final notes faded into the air, the creature slowly lowered its head. \"You have a kind heart, mortal,\" it rumbled. \"But Eldoria is cursed. Leave it be.\"\n",
              "\n",
              "Elara nodded, her eyes filled with understanding. She realized that Eldoria's true riches were not material, but rather the wisdom and knowledge that its people had possessed. She turned and began her descent from the mountains, carrying with her a newfound respect for the legends she had sought to uncover. Though she didn't find gold or jewels, she discovered something far more valuable: the courage to follow her dreams and the wisdom to know when to turn back. The secrets of Eldoria would remain undisturbed, protected by the guardian and the echoes of a beautiful melody.\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from IPython.display import Markdown\n",
        "\n",
        "MODEL_ID = \"gemini-2.5-flash\" # @param [\"gemini-2.5-flash-lite,\"gemini-2.5-flash\",\"gemini-2.5-pro\",\"gemini-3-pro-preview\"] {\"allow-input\":true}\n",
        "prompt = \"Generate a 10 paragraph fantasy story. Include at least 2 named characters and 2 named locations. Give as much detail in the story as possible.\"\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=prompt\n",
        "    )\n",
        "story = response.text\n",
        "Markdown(story)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sShzxm3JNm6M"
      },
      "outputs": [],
      "source": [
        "from typing_extensions import TypedDict  # in python 3.12 replace typing_extensions with typing\n",
        "\n",
        "class Character(TypedDict):\n",
        "  name: str\n",
        "  description: str\n",
        "  alignment: str\n",
        "\n",
        "class Location(TypedDict):\n",
        "  name: str\n",
        "  description: str\n",
        "\n",
        "class TextSummary(TypedDict):\n",
        "  synopsis: str\n",
        "  genres: list[str]\n",
        "  locations: list[Location]\n",
        "  characters: list[Character]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QGdJnd0AOKbu"
      },
      "outputs": [],
      "source": [
        "prompt = f\"\"\"\n",
        "Generate summary of the story. With a list of genres locations and characters.\n",
        "\n",
        "{story}\"\"\"\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=prompt,\n",
        "    config={\n",
        "        \"response_mime_type\": \"application/json\",\n",
        "        \"response_schema\": TextSummary\n",
        "        }\n",
        "    )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d5tOgde6ONo3"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'characters': [{'alignment': 'Good',\n",
            "                 'description': 'A cartographer and adventurer seeking the '\n",
            "                                'lost city of Eldoria.',\n",
            "                 'name': 'Elara'},\n",
            "                {'alignment': 'Neutral',\n",
            "                 'description': 'A creature of stone and shadow tasked with '\n",
            "                                'protecting the secrets of Eldoria.',\n",
            "                 'name': 'Guardian of the Hidden Passage'}],\n",
            " 'genres': ['Fantasy', 'Adventure'],\n",
            " 'locations': [{'description': 'A treacherous mountain range with jagged '\n",
            "                               'peaks, dangerous paths, and a hidden passage '\n",
            "                               'to Eldoria.',\n",
            "                'name': \"Dragon's Tooth Mountains\"},\n",
            "               {'description': 'A legendary, vanished civilization rumored to '\n",
            "                               'hold unimaginable riches and powerful magic.',\n",
            "                'name': 'Eldoria (Lost City)'},\n",
            "               {'description': 'A village where tales of Eldoria are whispered '\n",
            "                               'in taverns.',\n",
            "                'name': 'Whisperwind Village'}],\n",
            " 'synopsis': 'Elara, a cartographer and adventurer, seeks the lost city of '\n",
            "             \"Eldoria, following an ancient map through the Dragon's Tooth \"\n",
            "             'mountains. She faces treacherous terrain and a guardian '\n",
            "             'creature, ultimately using music to connect with the guardian '\n",
            "             \"and realizing that Eldoria's true value lies in its wisdom, not \"\n",
            "             'material riches. She chooses to leave Eldoria undisturbed, '\n",
            "             'gaining newfound courage and respect for legends.'}\n"
          ]
        }
      ],
      "source": [
        "from pprint import pprint\n",
        "\n",
        "pprint(response.parsed)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FhFfzDMk36aI"
      },
      "source": [
        "## Summary\n",
        "\n",
        "In this example, you used the Gemini API to extract key information from a story. This information could be fed into a structured database or used as a prompt for other writers to create their own versions.\n",
        "\n",
        "This technique of converting large open-ended text to structured data works across other formats too, not just stories.\n",
        "\n",
        "Please see the other notebooks in this directory to learn more about how you can use the Gemini API for other JSON related tasks."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "Text_Summarization.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
